#include "TransRadix.h"



void TransRadix::executeFFT() { executeFFT(false); }

void TransRadix::executeFFT(bool onlyComm) {



	int s=0;
	int lgn = log2(numPoints);
	int lgp = log2(numNodes);

	//int globalI = rank << (lgn - lgp);


	//ignore computation steps
	if (onlyComm) {
		s = lgn;
	}


	for (; s < lgp; s++) {

		int bitmask =  (numPoints-1) >> (lgn-s-1);

		for (int i=0; i < numLocalPoints; i++) {
			int ind0 = i*numNodes + rank;
			int ind1 = ind0 ^ (1 << (lgn-s-1));

			if (ind0 < ind1) {	

				//calculate Omega
				int r = bitRev(ind0,numPoints);
				int omega_power = (bitmask&r) << ((lgn-1)-(s+1)+1);
				Complex omega = FFTEngine::omega(numPoints,omega_power);
				

				int ind0_local = cyclic_global2localId(ind0);
				int ind1_local = cyclic_global2localId(ind1);

				Complex u = localData[ind0_local];
				Complex t = omega*localData[ind1_local];
					
				localData[ind0_local] = u + t;
				localData[ind1_local] = u - t;
			}
		}

	}


	
	//printLocalData();	
	


	
	//if (s == lgn) {
	//	return;
	//}



	//transpose
	//MPI_Alltoall(localData,2,MPI_DOUBLE,localBuff,2,MPI_DOUBLE,MPI_COMM_WORLD);

	int steps = numLocalPoints / numNodes;
	for (int i=0; i < steps; i++) {
		MPI_Alltoall(&(localData[i]),2,MPI_DOUBLE,&(localBuff[i]),2,MPI_DOUBLE,MPI_COMM_WORLD);
		//MPI_Alltoallv(&(localData[i]),sendCounts,sendDisp,MPI_DOUBLE,
		//		&(localBuff[i]),recvCounts,recvDisp,MPI_DOUBLE,
		//		MPI_COMM_WORLD);
	}

	//swap localBuff and localData
	Complex *tmp = localData;
	localData = localBuff;
	localBuff = tmp;


	


	//printLocalData();	






	

	for (; s < lgn; s++) {
		
		int bitmask =  (numPoints-1) >> (lgn-s-1);

		for (int i=0; i < numLocalPoints; i++) {
			int ind0 = rank*numLocalPoints + i;
			int ind1 = ind0 ^ (1 << (lgn-s-1));

			if (ind0 < ind1) {	


				//calculate Omega
				int r = bitRev(ind0,numPoints);
				int omega_power = (bitmask&r) << ((lgn-1)-(s+1)+1);
				Complex omega = FFTEngine::omega(numPoints,omega_power);
				//printf("s=%d ind0=%d ind1=%d OmegaPower=%d\n",s,ind0,ind1,omega_power);

				int ind0_local = blocked_global2localId(ind0);
				int ind1_local = blocked_global2localId(ind1);

				Complex u = localData[ind0_local];
				Complex t = omega*localData[ind1_local];
					
				localData[ind0_local] = u + t;
				localData[ind1_local] = u - t;
			}
		}
	
	}


 	
}

